#ifndef H_NYMPHAEA_MATRICES_MATRIX
#define H_NYMPHAEA_MATRICES_MATRIX
/*
 * project: nymphaea
 * module: matrices::matrix
 * purpose: for universal matrix interface
 * creation date: 2010-MAY-15
 * created by: kaby<entelechie@gmail.com>
 * license: GNU General Public License v3
 */
#include <vector>
#include <string>

#include <gsl/gsl_matrix.h>
#include <gsl/gsl_permutation.h>


namespace nymphaea
{
namespace matrices
{

class Matrix
{
public:
	Matrix(size_t row, size_t col);
	Matrix(const Matrix& ins);
	Matrix(const gsl_matrix* const data);
	~Matrix();

	size_t get_row_size() const;
	size_t get_col_size() const;

	Matrix get_row_by_idx(size_t idx) const;
	Matrix get_col_by_idx(size_t idx) const;

	double get_element_by_idx(size_t r_dix, size_t c_idx) const;
	void set_element_by_idx(size_t r_idx, size_t c_idx, double val);

	void set_all(double val);

	Matrix get_transposed() const;
	Matrix get_inverse();
	Matrix get_lu_decomp();
	double get_determinant();

	double sum() const;

	template<class Func>
	void transform(const Func& func);

	Matrix operator*(const Matrix& other) const;
	Matrix operator/(const Matrix& other) const;
	Matrix operator+(const Matrix& other) const;
	Matrix operator-(const Matrix& other) const;
	bool operator==(const Matrix& other) const;

	std::vector<double> row_to_vector(size_t idx) const;
	std::vector<double> col_to_vector(size_t idx) const;

	const std::string dump_to_bytes() const;
	int load_from_bytes(const std::string& data);
private:
	gsl_matrix* mpMatrix;
	gsl_matrix* mpInverse;
	gsl_matrix* mpLUDecomp;
	gsl_permutation* mpPerm;
	double mDeterminant;

	size_t mRowSize;
	size_t mColSize;

	void cal_LUDecomp_deter_perm();
	void reset_inverse_LUDecomp_deter_perm();
};

template<class Func>
void Matrix::transform(const Func& func)
{
	for(size_t i = 0; i < get_row_size(); ++i){
		for(size_t j = 0; j < get_col_size(); ++j){
			set_element_by_idx(i, j, func(get_element_by_idx(i, j)));
		}
	}
	return;
}



}
}

#endif
